package org.sdnstproject.interlayer.OF13Protocal;

import java.util.HashMap;
import org.projectfloodlight.openflow.exceptions.OFParseError;
import org.projectfloodlight.openflow.types.MacAddress;
import org.projectfloodlight.openflow.types.U32;
import org.projectfloodlight.openflow.util.HexString;
import org.sdnstproject.interlayer.utils.Utils;

import io.netty.buffer.ByteBuf;

public class FuPortDesc {
	/*OFPortStatusVer13(xid=0, reason=DELETE, 
	 * desc=OFPortDescVer13(portNo=2, hwAddr=6e:c1:95:1f:18:58, name=s1-eth2, config=[], 
	 * state=[], curr=[PF_10GB_FD, PF_COPPER], advertised=[], supported=[], peer=[], 
	 * currSpeed=10000000, maxSpeed=0))
	 * */
	public int portNo = 2;
	public long hwAddr = 0x0000FFFFFFFFFFFFL;//BROADCAST_VAL
	public String name = "s1-eth2";
	/**
	 * 0,1,4,20,40,5,21,24,41,44,60,25,61,45,64,65,
	 * 80000000,80000001,80000004,80000020,80000040,8000005,80000021,
	 * 80000024,80000041,80000044,80000060,80000025,80000061,80000045,
	 * 80000064,80000065
	 * */
	public int config = 0x0;
	private int[] configFuzzingVal=new int[]{0,1,4,20,40,5,21,24,41,44,60,25,61,45,64,65,
			 80000000,80000001,80000004,80000020,80000040,8000005,80000021,
			 80000024,80000041,80000044,80000060,80000025,80000061,80000045,
			 80000064,80000065};
	/**
	 * 0,1,2,4,3,5,6,7
	 * */
	public int state = 0x0;
	public int[] stateFuzzingVal = new int[] {0,1,2,4,3,5,6,7};
	public int curr =0x840;
	public int advertised =0x0;
	public int supported =0x0;
	public int peer =0x0;
	public long currSpeed =10000000;
	public long maxSpeed =0;
	
	public MacAddress gethwAddrObject() {
		return MacAddress.of(hwAddr);
	}
	
	public MacAddress gethwAddrObject(long hwAddr) {
		return MacAddress.of(hwAddr);
	}
	
	public MacAddress gethwAddrObject(String hwAddr) {
		return MacAddress.of(hwAddr);
	}
	
	public String hwAddrtoString() {
        return HexString.toHexString(hwAddr, 6);
    }

	public String getFuzzingValue(String attribute) {
		if(attribute.equals("config")) {
			return "int";
		}
		return null;
	}
	
	public int[] getconfigFuzzingVal() {
		return configFuzzingVal;
	}
	
	public FuPortDesc() {
		
	}
	public FuPortDesc(ByteBuf bb) {
        this.portNo = bb.readInt();
        // pad: 4 bytes
        bb.skipBytes(4);
        try {
        	this.hwAddr = MacAddress.read6Bytes(bb).getLong();
		} catch (OFParseError e) {
			e.printStackTrace();
		}
        // pad: 2 bytes
        bb.skipBytes(2);
        this.name = Utils.readFixedLengthString(bb, 16);
        this.config = bb.readInt();
        this.state = bb.readInt();
        this.curr = bb.readInt();
        this.advertised = bb.readInt();
        this.supported = bb.readInt();
        this.peer = bb.readInt();
        this.currSpeed = U32.f(bb.readInt());
        this.maxSpeed = U32.f(bb.readInt());
    }
		
	public FuPortDesc(int portNo, long hwAddr, String name, int config, int state, int curr, int advertised, int supported, int peer, long currSpeed, long maxSpeed) {
        this.portNo = portNo;
        this.hwAddr = hwAddr;
        this.name = name;
        this.config = config;
        this.state = state;
        this.curr = curr;
        this.advertised = advertised;
        this.supported = supported;
        this.peer = peer;
        this.currSpeed = currSpeed;
        this.maxSpeed = maxSpeed;
    }
	public HashMap<String, String> PortDescFields = new HashMap<String, String>() {
		{
			put("port_no","int");
			put("hw_addr","long");
			put("name","String");
			put("config","int");
			put("state","int");
			put("curr","int");
			put("advertised","int");
			put("supported","int");
			put("peer","int"); 
			put("curr_speed","long");
			put("max_speed","long");
		}
	};
	
	public FuPortDesc setMaxSpeed(long maxSpeed) {
		this.maxSpeed = maxSpeed;
		return this;
	}

	public FuPortDesc setPortNo(int portNo) {
		this.portNo = portNo;
		return this;
	}

	public FuPortDesc setHwAddr(long hwAddr) {
		this.hwAddr = hwAddr;
		return this;
	}

	public FuPortDesc setName(String name) {
		this.name = name;
		return this;
	}

	public FuPortDesc setConfig(int config) {
		this.config = config;
		return this;
	}

	public FuPortDesc setState(int state) {
		this.state = state;
		return this;
	}

	public FuPortDesc setCurr(int curr) {
		this.curr = curr;
		return this;
	}

	public FuPortDesc setAdvertised(int advertised) {
		this.advertised = advertised;
		return this;
	}

	public FuPortDesc setSupported(int supported) {
		this.supported = supported;
		return this;
	}

	public FuPortDesc setPeer(int peer) {
		this.peer = peer;
		return this;
	}

	public FuPortDesc setCurrSpeed(long currSpeed) {
		this.currSpeed = currSpeed;
		return this;
	}


    public void writeTo(ByteBuf bb) {
    	bb.writeInt(this.portNo);
        // pad: 4 bytes
        bb.writeZero(4);
        this.gethwAddrObject(this.hwAddr).write6Bytes(bb);
        // pad: 2 bytes
        bb.writeZero(2);
        Utils.writeFixedLengthString(bb, this.name, 16);
        bb.writeInt(this.config);
        bb.writeInt(this.state);
        bb.writeInt(this.curr);
        bb.writeInt(this.advertised);
        bb.writeInt(this.supported);
        bb.writeInt(this.peer);
        bb.writeInt(U32.t(this.currSpeed));
        bb.writeInt(U32.t(this.maxSpeed));
    }
    public void write(ByteBuf bb, FuPortDesc message) {
    	bb.writeInt(message.portNo);
        // pad: 4 bytes
        bb.writeZero(4);
        message.gethwAddrObject(message.hwAddr).write6Bytes(bb);
        // pad: 2 bytes
        bb.writeZero(2);
        Utils.writeFixedLengthString(bb, message.name, 16);
        bb.writeInt(message.config);
        bb.writeInt(message.state);
        bb.writeInt(message.curr);
        bb.writeInt(message.advertised);
        bb.writeInt(message.supported);
        bb.writeInt(message.peer);
        bb.writeInt(U32.t(message.currSpeed));
        bb.writeInt(U32.t(message.maxSpeed));
    }
	
	@Override
    public String toString() {
        StringBuilder b = new StringBuilder("OFPortDescVer13(");
        b.append("portNo=").append(portNo);
        b.append(", ");
        b.append("hwAddr=").append(hwAddrtoString());
        b.append(", ");
        b.append("name=").append(name);
        b.append(", ");
        b.append("config=").append(config);
        b.append(", ");
        b.append("state=").append(state);
        b.append(", ");
        b.append("curr=").append(curr);
        b.append(", ");
        b.append("advertised=").append(advertised);
        b.append(", ");
        b.append("supported=").append(supported);
        b.append(", ");
        b.append("peer=").append(peer);
        b.append(", ");
        b.append("currSpeed=").append(currSpeed);
        b.append(", ");
        b.append("maxSpeed=").append(maxSpeed);
        b.append(")");
        return b.toString();
    }
}
